李守中

Linux 硬盘与文件系统

Table of Contents

1. EXT4 文件系统

1.1. df -h 命令报告 Size > Used + Avail

创建文件系统时,ext 系列文件系统默认保留 5% 的空间仅供 root 用户使用。目的是在极端情况下为 root 用户提供操作空间。

执行 tune2fs -l <device-partition> 查看设备分区的信息。其中 Reserved block count 记录了为 root 用户保留的 block 的数量。

执行 tune2fs -m 0 <device-partition> 可以释放分区所有的保留空间。

注: mdadm raid 设备 (比如 /dev/md0) 按分区处理。

2. 驱动器命名

软盘驱动器命名:

  • 第一个软盘驱动器被命名为 /dev/fd0
  • 第二个软盘驱动器被命名为 /dev/fd1

SCSI 驱动器命名:

  • 第一个 SCSI 驱动器被命名为 /dev/sda
  • 第二个 SCSI 驱动器被命名为 /dev/sdb
  • 第一个 SCSI 光盘驱动器被命名为 /dev/scd0 (也叫 /dev/sr0)

IDE 驱动器命名:

  • 主 IDE 控制器下的主硬盘被命名为 /dev/hda
  • 主 IDE 控制器的从盘命名为 /dev/hdb
  • 第二个 IDE 控制器的主硬盘和从硬盘分别被叫做 /dev/hdc 和 /dev/hdd
  • 较新的 IDE 控制器实际上有两个通道扮演着两个控制器的角色

硬盘分区通过在硬盘名称后面附加一个十进制数字来表示: sda1 和 sda2 代表系统里的第一个 SCSI 硬盘驱动器的第一个和第二个分区。

给一个例子。假设系统有两个 SCSI 硬盘,一个 SCSI 地址是 2,另外一个地址是 4。第一个硬盘 (在 2 上) 会被命名为 sda,第二个 (在 4 上) 会被命名为 sdb。如果 sda 驱动器有 3 个分区,它们将被命名为 sda1, sda2 和 sda3。这个规律同样适用于 sdb 及其分区。

注意: 如果有两个 SCSI 主机总线适配器 (控制器),设备的顺序可能会比较混乱。最好的解决方案是观察引导信息。如果能知道驱动器型号和/或者容量,也能容易地分辨设备。

3. 扇区与 4K 对齐的分区

最初的物理扇区 (sector) 大小是 512B,这是硬盘一次读写行为操作的最小单位。后来随着硬盘容量越来越大,物理扇区的大小变成了 4096B。

然而,有很多程序依旧按照 512B 的扇区大小来与硬盘交互。为了兼容这些程序,硬盘厂家在硬盘驱动中添加了兼容 512B 扇区的操作逻辑,这种 512B 的扇区叫做逻辑扇区。

比如,很多 boot loader 在代码层面写死了一次只操作 512B 的数据。

实际上,如果程序真的一次操作 512B 的数据,那么硬盘必须先把这 512B 所在的 4K 扇区读到硬盘的缓存中,再从缓存里的这 4K 数据中找要程序要的这 512B 数据返回给程序。

如果这 512B 数据需要修改,程序把这 512B 数据发给硬盘后,如果硬盘在读取这 512B 数据时产生的缓存没有失效,就直接把这 512B 数据覆盖回缓存中的这 4K 数据对应的位置,再把这 4K 数据从硬盘缓存写回到硬盘。如果缓存失效,就必须先把这 512B 数据所在的 4K 扇区中的数据读到缓存里才能继续下一步覆盖、回写的操作。

还有一种更差的情况: 程序要读写的这 512B 数据横跨了两个扇区。这时候就需要把两个 4K 扇区的数据都读出来,然后再在每个扇区中取程序需要的那部分拼起来再返回给程序。

让分区 4K 对齐的目的就是避免出现程序要操作的数据横跨了两个扇区的情况。

操作系统需要使用文件系统来与硬盘交互,而文件系统一次操作的最小单位是一个 block,它的大小可以在建立文件系统时调整。通常,一个 block 的大小是 4K,就是硬盘上一个物理扇区的大小。

所以,让分区 4K 对齐的目的是,在文件系统与硬盘交互时,文件系统每次读写操作的对象正好是一个物理扇区。

前面说过,物理扇区是硬盘一次读写操作的最小单元,即,按照硬盘的读写逻辑,可以认为硬盘是由无数个物理扇区组成的。

如果一个分区从某个扇区的中间开始,那么文件系统要读写的每个 4K block 都会横跨两个 4K 扇区。但如果一个分区从某一个扇区开始的位置开始,从某一个扇区结束的位置结束,那么文件系统要读写的每个 4K block 就只有一个扇区。

所以,简单来说,在硬盘分区时,让分区的边界处于某个物理扇区的边界,就是 4K 对齐。

如何使用分区工具在分区时做到 4K 对齐,看下一节。

4. 硬盘分区

4.1. 硬盘分区工具

debian 系统中,root 以外的用户没有把 /usr/sbin 加入环境变量,所以用 fdisk 命令时要自己补全路径。

查看硬盘信息 /usr/sbin/fdisk -l ,确定要分区的硬盘设备后,执行 /usr/sbin/fdisk /dev/<device> 后进入命令行。按需输入命令:

  • m 查看帮助信息。
  • p 显示现有分区信息。
  • n 创建新分区。
  • d 删除现有分区。
  • t 修改分区类型。
  • l 查看所有分区类型。
  • w 保存并退出。

cat /proc/partitions 可以查看目前分区情况。

一些老旧系统上的旧版 fdisk 工具只支持 mbr 格式的分区方式,这种方式只能处理 2T 容量及以下的硬盘,如果用它处理 2T 以上的盘,硬盘将只有 2T 可用。当然,新版的 fdisk 已经支持了 gpt 格式的分区方式来处理 2T 以上容量的硬盘。

在这些老旧系统上执行 apt install parted 使用 parted 可以管理容量大于 2T 的硬盘。

执行 parted /dev/<device> 进入命令交互模式,开始分区:

  1. (parted) mklabel gpt 创建 GPT 分区表
  2. (parted) mkpart <primary | logical | extended> [ext4 | xfs |...] <[0% 100%] | [1K,M,G,T 5K,M,G,T]> 创建分区
  3. (parted) name <partition number> <name> 重命名分区
  4. (parted) print 查看硬盘分区
  5. (parted) quit 退出

4.2. 让分区 4K 对齐

给一个硬盘分区的例子,这个硬盘的分区已经做好了 4K 对齐:

root@gen10:~# fdisk -l /dev/sdc
Disk /dev/sdc: 7.28 TiB, 8001563222016 bytes, 15628053168 sectors
Disk model: HGST HUS728T8TAL
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 99CE863D-073B-CA4B-8272-DBE1C94B7E43

Device     Start         End     Sectors  Size Type
/dev/sdc1   2048 15569258495 15569256448  7.3T Linux filesystem

这是一块西数 HC320 8T 硬盘,从例子第 5 行可以看到,硬盘的逻辑扇区的大小是 512B,物理扇区的大小是 4096B。

还有另一种获取扇区大小的方法:

root@gen10:~# cat /sys/class/block/sdc/queue/logical_block_size
512
root@gen10:~# cat /sys/class/block/sdc/queue/physical_block_size
4096

logical_block_size 的含义是内核进行读写操作的最小单元,physical_block_size 的含义是硬盘执行读写操作的最小单元。也就是说,此时,内核使用 512B 的扇区大小与硬盘交互 (即,使用上文提到的硬盘驱动中的 512B 逻辑扇区兼容层)。

硬盘的扇区号从 0 开始,并且,从前面的信息可以知道,当前系统使用 512B 大小的逻辑扇区与硬盘交互。那么第一个物理扇区 (4096B) 由前 8 个逻辑扇区 (512B) 组成,这 8 逻辑扇区的扇区号是 0-7。以此类推,第二个物理扇区对应的逻辑扇区的扇区号是 8-15。

那么,不难推出:

  1. 如果一个分区的起始逻辑扇区号可以被 8 整除,那么这个分区一定开始于某个物理扇区的开始
  2. 如果一个分区的逻辑扇区数量可以被 8 整除,那么这个分区中一定含有整数个物理扇区

满足以上两个条件就可以认为这个分区做好了 4K 对齐。

注: 注意细节,第一个关键字是扇区号,它从零开始;第二个关键字是扇区数量,它是 fdisk 命令输出中 Sectors 字段对应的值。

在实际操作时 fdisk 做了一些优化: 第一个分区默认的逻辑扇区的扇区号是 2048,它是 fdisk 命令输出中 Start 字段对应的值,它默认满足第一个条件。第二个分区默认开始于第一个分区的最后一个逻辑扇区的下一个逻辑扇区。在分第二个分区时要做好计算。

4.3. 让内核重新读取分区表

  • debian:
    • partprobe /dev/sdb 重读分区表
    • partprobe 强制重读所有设备
  • centos 6 / 7:
    • kpartx -a /dev/sdbkpartx -af /dev/sdb 重读分区表
    • kpartx -akpartx -af 强制重读所有设备

注: 一次执行不成功可执行多次。

5. 硬盘分区上的文件系统

注 1: 一些程序如果在磁盘上检测到了有效的文件系统或 raid 签名 (magic string),就会停止操作该硬盘。如果硬盘之前被用在其他的系统中,则最好先擦除硬盘上的文件系统信息或 raid 签名。

比如,如果硬盘以前在 VMware 全家桶上使用,现在要将其加入 PVE 或者 Ceph 系统。如果硬盘没有做全盘写 0 这种彻底的数据擦除,那么在硬盘初始化阶段中,系统在硬盘中找到了 VMFS_volume_member 信息就会导致初始化失败。解决这个问题需要清理硬盘上已有的文件系统信息或 raid 签名。

手动执行 dd 命令是一种方式,比如 VMFS volume memberVMFS filesystem 的超级块分别位于距离分区起始位置的 1024 KiB2048 KiB 偏移量处,因此 dd if=/dev/zero of=/dev/<disk-device> bs=4M count=1 可以擦除硬盘前 4 MiB 的块来清除残留数据。

当然,也可以使用 wipefs 命令来完成这一过程,但这个命令并不是每个操作系统中都有。

最后可执行 lsblk -f 确认文件系统的类型。

注 2: linux 内核在 4.1 之后支持了 xfs 文件系统,但是这个文件系统在 5.x 的内核中才比较稳定。使用 xfs 需要系统内安装有 xfsprogs

5.1. 为分区创建文件系统

mkfs 是 util-linux 包的一部分,可以用来创建许多不同种类的文件系统。它只是一个包装工具,为创建不同的文件系统提供了统一的的接口。

mke2fs 是 e2fsprogs 包的一部分,可以用来创建 ext2/3/4 文件系统。创建 ext2/3/4 文件系统时,mkfs 会调用 mke2fs。

/usr/sbin/mkfs.<fs-type> 可以创建指定为 <fs-type> 格式的文件系统。比如 mkfs.ext4, mkfs.xfs 。但如果不加 <fs-type> 参数只执行 mkfs 则默认创建 ext2 格式的文件系统。同时,util-linux 的文档中提到并不推荐使用 mkfs 的格式,应该使用 mkfs.<fs-type> 的格式。

/usr/sbin/mke2fs 的常用参数有:

  • -t {ext2 | ext3 | ext4} 指明要创建的文件系统的类型,默认值 ext2
    • mke2fs -t ext4 /dev/<device-partition> = mkfs -t ext4 /dev/<device-partition> = mkfs.ext4 /dev/<device-partition>
  • -b {1024 | 2048 | 4096} 文件系统的块大小
  • -l <label> 指明卷标。卷标可以在 /usr/sbin/blkid <device> 命令的输出中查看
  • -j 创建有日志功能的文件系统 (就是创建 ext3 系统)
    • mke2fs -j /dev/<device-partition> = mkfs -t ext3 /dev/<device-partition> = mkfs.ext3 /dev/<device-partition>
  • -i <number> 指明多大字节的数据块创建一个 inode
  • -N <number> 指明要给文件系统创建的 inode 的数量
  • -m <number> 指定预留空间,数字为百分比。默认值 5%
  • -O <feature> 以指定的特性创建文件系统

5.2. 调整分区属性

ext 系列文件系统的卷标 (使用 e2fsprogs 包中的工具):

  • /usr/sbin/e2label /dev/<device-partition> 可以查看设备分区的卷标
  • /usr/sbin/e2label /dev/<device-partition> <label-name> 可将设备分区的卷标设置为 <label-name> 指定的值

xfs 文件系统的卷标 (使用 xfsprogs 包中的工具):

  • xfs_admin -l /dev/<device-partition> 查看卷标
  • xfs_admin -L <label-name> /dev/<device-partition> 可以将指定的设备分区的卷标设置为 <label-name> 指定的值

/usr/sbin/tune2fs [OPTION] <device> 命令是 e2fsprogs 包的一部分,可以查看或调整 ext2/3/4 文件系统的某些属性:

  • -l 列出超级块中的内容:
    • Filesystem features 已经启用的特性
    • Filesystem magic number 文件系统类型
    • Default mount options 默认的挂载选项
    • Filesystem state: clean 文件系统处于一致状态显示为 cleandirty 表示不一致:
      • 意外断电关机一定会有文件不完整,此时文件系统处于 dirty 状态
  • 修改指定文件系统的属性:
    • -j 将 ext2 升级为 ext3
    • -L <label> 修改卷标为 <label> 指定的值
    • -m <number> 不格式化分区的情况下,调整预留给 root 用户的空间的百分比
    • -O <feature> 开启或关闭某种特性
    • -o <mount-option> 调整默认挂载属性

注意: 块大小无法修改。

/usr/sbin/dumpe2fs -h <device-partition> 显示 ext 系列文件系统的属性信息。

/usr/sbin/blkid 查找文件系统:

  • <device-or-device-partition> 查看设备或分区上的文件系统的信息
  • -L <label> 根据 <label> 定位设备
  • -U <uuid> 根据 <uuid> 定位设备

5.3. 文件系统检测与修复

因进程意外终止或系统崩溃等原因导致文件写入操作非正常中止,可能造成文件损坏。此时应检测并修复文件系统,建议离线进行。

xfs 文件系统 (使用 xfsprogs 包中的工具):

  • 检测文件系统: xfs_ncheck /dev/<device-partition>
  • 修复文件系统: xfs_repair -v /dev/<device-partition>
  • 碎片整理:
    • 检查碎片程度: xfs_db -c frag -r /dev/<device-partition>
    • 进行碎片整理: xfs_fsr /dev/<device-partition>

ext 系列文件系统的 (e2fsprogs 包中的) 专用工具 e2fsck 可用于检查 exit2/exit3/exit4 文件系统,命令格式 e2fsck [option] <device>:

  • -y 所有疑问均回答 yes
  • -f 即使文件系统处于 clean 状态也强制进行检测

/usr/sbin/fsck 和 mkfs 类似,它包装了各种文件系统检测工具,为用户提供了一个统一接口:

  • -t <file-system-type> 指明文件系统的类型:
    • fsck -t ext4 = fsck.ext4
  • -a 无需交互,自动修复所有错误。修复时会自动删除未写完的文件,不推荐用
  • -r 交互式修复

5.4. 挂载设置

文件系统挂载到根目录上的某个目录之后,才能通过该目录访问文件系统,这个目录就是挂载点。挂载点必须:

  • 事先存在
  • 不能使用被其他进程使用的目录
  • 挂载点下原有的文件将被隐藏

mount [option] [-t vfstype] [-o options] <device> <dir> 命令可以被用于挂载文件系统到挂载点:

  • option 部分:
    • -r 意为 read only 只读挂载 (比如光驱)
    • -w 意为 read & write 读写挂载,是默认选项
    • -n 禁止设备的挂载或卸载的操作同步更新至 /etc/mtab 。默认会同步
  • -t 选项:
    • -t 指明要挂载的设备上的文件系统的类型,多数情况下可省略,此时 mount 命令会通过 blkid 命令来识别要挂载的设备的文件系统的类型
    • -L <label> 挂载时用卷标指明要挂载的设备
    • -U <uuid> 挂载时用 uuid 指明要挂载的设备
  • -o 挂载选项:
    • sync / async 采用 同步 / 异步 写入
    • atime / noatime:
      • atime 当文件被访问时,马上更新文件的时间戳
      • noatime 不更新文件时间戳
    • diratime / nodiratime:
      • diratime 当目录被访问时,马上更新目录的时间戳
      • nodiratime 不更新目录时间戳
    • remount 重新挂载文件系统
    • acl 支持使用 facl (文件访问控制) 功能
    • ro 只读挂载
    • rw 读写挂载
    • dev / nodev 此设备上 允许 / 不允许 创建设备文件 (/dev/ 下的文件为设备文件)
    • exec / noexec 是否允许运行此设备上的程序文件
    • auto / noauto 是否允许自动挂载
    • user / nouser 是否允许普通用户挂载此文件系统
    • suid / nosuid 是否允许程序文件上的 suid 和 sgid 特殊权限生效
    • relatime / norelatime 是否参考文件的修改时间来更新 inode 的访问时间
    • defaults 使用默认选项: rw, suid, dev, exec, auto, nouser, async, relatime

注: 可以将目录绑定至另一个目录上,作为临时访问入口 mount --bind <target-dir> <entrance-dir>

查看当前系统所有已经挂载的设备:

  • 查看挂载表: cat /etc/mtab
  • 格式化解析挂载表: mount
  • 查看保存在内核中的挂载信息: cat /proc/mounts

挂载光盘 / U 盘:

  • mount -r /dev/cdrom <mount_point>
  • 光盘设备文件 /dev/cdrom/dev/dvd:
    • /dev/cdrom 是一个链接,指向真正的光盘文件
    • 具体哪个才是要找的设备则需要参考存储容量来反推

挂载本地的回环设备 (直接挂载 ISO 文件): mount -o loop <path-to-iso-file> <path-to-mount-point>

5.5. 取消挂载

命令 umount {<device> | <dir>} 可以卸载设备。

注: 正在被进程访问的挂载点无法被取消挂载。

取消挂载失败:

  1. 找到哪个进程正在使用挂载点:
    • 显示哪个进程正在使用挂载点里的数据: lsof <path-to-mount-point>
    • 显示哪个用户的什么进程正在使用挂载点的数据: fuser -v <path-to-mount-point>
  2. 干掉所有使用挂载点的进程: fuser -km <path-to-mount-point>

5.6. 开机自动挂载文件系统

/etc/fstab 文件中,每行 6 个字段定义了一个要开机挂载的文件系统及其相关属性:

  1. 要挂载的文件设备:
    1. 设备文件
    2. LABEL
    3. UUID
    4. 伪文件系统
  2. 挂载点:
    1. 文件夹路径
    2. swap 分区的挂载点为 swap
  3. 文件系统类型
  4. 挂载选项:
    1. defaults 表示使用默认挂载选项
    2. 如果要指明多个挂载选项,每个选项之间用逗号隔开。比如 defaults, acl, noatime, noexec
  5. 转储 (备份) 频率:
    1. 0 表示从不删除
    2. 1 每天备份一次
    3. 2 每隔一天备份一次
  6. 自检次序:
    1. 0 不自检
    2. 1 第一个自检 (通常根文件系统才用 1)
    3. 2 次级自检 (多个文件系统可以有相同的自检次序)
    4. 0-9 自检等级有 0 - 9 多个等级

/etc/fstab 文件中的自动挂载配置实例:

  • 通过指定设备: /dev/sdb1 /mnt/400GIntelS3710 xfs defaults 0 0
  • 通过指定设备 uuid: UUID=cb111...c89c /mnt ext4 defaults,acl 0 0
  • 通过指定设备 label: LABEL=MYDATA /mnt ext4 defaults 0 0

更改完成后,执行 mount -a 即可挂载 /etc/fstab 文件里指明的所有设备。



Last Update: 2023-11-06 Mon 22:04

Generated by: Emacs 28.2 (Org mode 9.5.5)   Contact: [email protected]

若正文中无特殊说明,本站内容遵循: 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议